package com.dusk.net
{
    import com.dusk.game.Logger;
    import com.dusk.util.ArrayUtil;
    import com.dusk.util.UtilBase;
    import flash.media.Sound;
    import flash.utils.ByteArray;
    import flash.utils.Dictionary;
    
    public class AssetManager
    {
        
        private static var _ins:AssetManager;
        
        private var _assetMap:Dictionary;
        
        private var _onCompleteFuncList:Array = [];
        
        private var _onProgressFuncList:Array = [];
        
        private var _onIOErrorFuncList:Array = [];
        
        private var _readyLoadAssetList:Array = [];
        
        public static function getIns():AssetManager
        {
            if (!_ins)
            {
                _ins = new AssetManager();
            }
            return _ins;
        }
        
        public function AssetManager()
        {
            _assetMap = new Dictionary();
        }
        
        public function addCallback(onComplete:Function = null, onProgress:Function = null, onIOError:Function = null):void
        {
            if (onComplete && !ArrayUtil.contains(_onCompleteFuncList, onComplete)) _onCompleteFuncList.push(onComplete);
            if (onProgress && !ArrayUtil.contains(_onProgressFuncList, onProgress)) _onProgressFuncList.push(onProgress);
            if (onIOError && !ArrayUtil.contains(_onIOErrorFuncList, onIOError)) _onIOErrorFuncList.push(onIOError);
        }
        
        public function addAssetToQueue(url:String, type:String, bytes:ByteArray = null, onComplete:Function = null, onProgress:Function = null, onIOError:Function = null):void
        {
            var item:AssetItem = new AssetItem();
            item.url = url;
            item.type = type;
            item.bytes = bytes;
            _readyLoadAssetList.push(item);
            addCallback(onComplete, onProgress, onIOError);
        }
        
        /**
         * 每次调用此函数会新建一个线程，清空所有的CallBack集合和AssetList集合
         */
        public function startLoadQueue():void
        {
            var vo:ThreadVO = new ThreadVO();
            vo.setCallBacks(_onCompleteFuncList, _onProgressFuncList, _onIOErrorFuncList);
            _readyLoadAssetList = _readyLoadAssetList.filter(function (item:AssetItem, ...rest):Boolean
            {
                return !hasCache(item.url);
            });
            for each(var i:AssetItem in _readyLoadAssetList)
            {
                _assetMap[i.url] = i;
            }
            vo.setAssetList(_readyLoadAssetList);
            vo.start();
            
            _onCompleteFuncList = [];
            _onProgressFuncList = [];
            _onIOErrorFuncList = [];
            _readyLoadAssetList = [];
        }
        
        public function loadAsset(url:String, type:String, bytes:ByteArray = null, onComplete:Function = null, onProgress:Function = null, onIOError:Function = null):void
        {
            addAssetToQueue(url, type, bytes, onComplete, onProgress, onIOError);
            startLoadQueue();
        }
        
        public function loadAssets(urls:Array, type:String, bytes:ByteArray = null, onComplete:Function = null, onProgress:Function = null, onIOError:Function = null):void
        {
            for each (var i:String in urls)
            {
                addAssetToQueue(i, type, bytes, onComplete, onProgress, onIOError);
            }
            startLoadQueue();
        }
        
        public function hasCache(url:String):Boolean
        {
            return Boolean(_assetMap[url]);
        }
        
        public function getAsset(url:String):AssetItem
        {
            return _assetMap[url];
        }
        
        public function getSound(url:String):Sound
        {
            if (hasCache(url))
            {
                return (_assetMap[url] as AssetItem).sound as Sound;
            }
            return null;
        }
        
        public function getJSON(url:String):Object
        {
            if (hasCache(url))
            {
                return (_assetMap[url] as AssetItem).json;
            }
            return null;
        }
        
        public function getXml(url:String):XML
        {
            if (hasCache(url))
            {
                return (_assetMap[url] as AssetItem).xml;
            }
            return null;
        }
        
        public function getClass(classKey:String):Object
        {
            for each (var i:AssetItem in UtilBase.getAllValue(_assetMap))
            {
                if (i.type == AssetType.SWF && i.hasClass(classKey))
                {
                    return i.getClass(classKey);
                }
            }
            return null;
        }
        
        public function getConfig(url:String):Object
        {
            if (hasCache(url) && _assetMap[url].type == AssetType.CONFIG)
            {
                return (_assetMap[url] as AssetItem).json;
            }
            return null;
        }
        
        public function getClassInstance(classKey:String):Object
        {
            for each (var i:AssetItem in UtilBase.getAllValue(_assetMap))
            {
                if (i.type == AssetType.SWF && i.hasClass(classKey))
                {
                    return i.getClassInstance(classKey);
                }
            }
            return null;
        }
        
        public function deleteAsset(url:String):void
        {
            if (hasCache(url))
            {
                var item:AssetItem = _assetMap[url];
                item.destroy();
                delete _assetMap[url];
            }
        }
        
        public function deleteAllAssets():void
        {
            for each(var key:String in UtilBase.getAllKeys(_assetMap))
            {
                var item:AssetItem = _assetMap[key];
                if (item.type == AssetType.SWF)
                {
                    continue;
                }
                item.destroy();
                Logger.log("delete key: " + key)
                delete _assetMap[key];
            }
            Logger.log("====== clear asset cache ======");
        }
    }
}